/**
 * Created by TangZK on 2015/5/13.
 */
var Server = require('socket.io');
var crypto = require('crypto');
var io = Server.listen(8090);
var util = require('util');
var kefu = io.of('/kefu');
var KeFuModel = require('./kefu_model.njs').KeFuModel;
//var myUtil = require('./MyUtil.njs').myUtil; // 用于获取ip信息

var userList = {}; // 用户列表，数据量大时，需换策略

/** 结构:
 * {
 *   user_id: int,
 *   join_id: int, // socket 通讯id
 *   user_name: string,
 *   status: enum,  //0为空闲，1为已分配未确认, 2为对话中
 *   callers: {
 *   	callerJoinId: lastChatTime // caller最后一次的聊天时间
 *   },
 *   job_number: int, 工号
 *   answer_number: int, 最大接听数量,
 *   group_id: int, // 分组ID
 *   job_sort: int 工行排序，此值越小，优先级越高
 * }
 */
var adminList = {}; // 管理员列表

var userHelper = {
	// 添加一个用户
	record: function (uo) {
		var tmp = {};
		tmp.uid = uo.uid; // uid为0的为访客
		tmp.username = uo.username;
		tmp.access_time = uo.access_time;
		tmp.ip = uo.ip;
		tmp.role = uo.role;
		tmp.join_id = uo.join_id;
		tmp.isReply = 0; // 当客服初始化界面时，会重复发送通知给访客客户端，通过此参数，如果已经回复了，就不再通知客户端了
		userList[uo.join_id] = tmp;
	},
	getUserInfo: function (joinId) {
		var userInfo = null;
		if (userList && userList[joinId]) {
			userInfo = userList[joinId];
		}
		return userInfo;
	},
	getUserAttr: function (joinId, attr) {
		var userInfo = this.getUserInfo(joinId),
			val = null;
		if (userInfo) {
			val = userInfo[attr];
		}
		return val;
	},
	setUserAttr: function (joinId, attr, val) {
		var userInfo = this.getUserInfo(joinId);
		if (userInfo) {
			userInfo[attr] = val;
		}
	}
};

var adminHelper = {
	// 获取一个可以应答访客的管理员
	catchOne: function () {
		var admin = null;
		if (Object.keys(adminList).length > 0) {
			for (var key in adminList) {
				var val = adminList[key];
				if (Object.keys(val.callers).length < val.answer_number) {
					val['status'] = 1;
					admin = val;
					break;
				}
			}
		}
		return admin;
	},
	/**
	 * 从某一分组里获取客服成员
	 * @param groupId
	 * @returns {*}
	 */
	catchOneFromGroup: function (groupId) {
		var me = this,
			groupSet = {};
		if (Object.keys(adminList).length > 0) {
			for (var key in adminList) {
				var val = adminList[key];
				if (val.group_id == groupId) {
					groupSet[key] = val;
				}
			}
		}
		var admin = me.filterData(groupSet);
		return admin;
	},
	changeStaus: function (joinId, statusCode) {
		if (Object.keys(adminList).length > 0) {
			if (adminList[joinId]) {
				adminList[joinId]['status'] = statusCode;
			}
		}
	},
	getAdminInfo: function (joinId) { // 判断管理员是否已经在列表里存在
		var info = false;
		if (adminList[joinId]) {
			info = adminList[joinId];
		}
		return info;
	},
	initAdminInfo: function (ao) { // 初始化管理员数据结构，向管理员列表里添加管理员
		if (ao && ao.user_id) {
			var me = this,
				adminId = ao.user_id,
				joinId = ao.join_id,
				admin_info = me.getAdminInfo(joinId);
			if (admin_info === false) {
				var struct = {};
				struct.user_id = adminId;
				struct.join_id = joinId;
				struct.user_name = ao.user_name;
				struct.status = 0;
				struct.callers = {};
				struct.answer_number = (ao.answer_number && ao.answer_number <= 20) ? ao.answer_number : 20;
				struct.job_number = ao.job_number;
				struct.group_id = ao.group_id;
				struct.job_sort = ao.job_sort;
				adminList[joinId] = struct;
			}
		}
	},
	getCallerList: function (joinId) { // 获取管理员应答的访客列表
		var me = this,
			info = me.getAdminInfo(joinId),
			callerList = null;
		if (info !== false && info.callers) {
			callerList = info.callers;
		}
		return callerList;
	},
	addCallerToList: function(adminJoinId, callerInfo) {
		var me = this,
			adminInfo = me.getAdminInfo(adminJoinId),
			callerJoinId = callerInfo.join_id;
		adminInfo.callers[callerJoinId] = callerInfo;
	},
	isJoinId: function (joinId) {
		var r = false;
		if (/^a\d+/.test(joinId)) {
			r = true;
		}
		return r;
	},
	getCallerInfo: function (joinId, callerJoinId) { //获取管理员应答过的某访客信息。
		var me = this,
			callerInfo = null,
			callerList = me.getCallerList(joinId);
		if (callerList && callerList[callerJoinId]) {
			callerInfo = callerList[callerJoinId];
		}
		return callerInfo;
	},
	getCallerNum: function (joinId) {
		var me = this,
			callerList = me.getCallerList(joinId),
			num = null;
		if (callerList) {
			num = Object.keys(callerList).length;
		}
		return num;
	},
	updateData: function () { // 检查并更新管理员的相关数据：访客列表，以及状态

	},
	sortByField: function (arr, field) {
		if (arr.length <= 1) {
			return arr;
		}
		var me = this,
			pivotIndex = Math.floor(arr.length / 2),
			pivot = arr.splice(pivotIndex, 1)[0],
			la = [],
			ra = [];
		for (var i = 0; i < arr.length; i++) {
			if (arr[i][field] < pivot[field]) {
				la.push(arr[i]);
			} else {
				ra.push(arr[i]);
			}
		}
		return me.sortByField(la, field).concat([pivot], me.sortByField(ra, field));
	},
	/**
	 * 从一组集合中，按条件筛选出一条信息
	 * @param dataSet
	 * @returns {*}
	 */
	filterData: function (dataSet) {
		var me = this,
			arr = [],
			data = null;
		// 先按工号进行排序
		for (var key in dataSet) {
			var val = dataSet[key];
			if (Object.keys(val.callers).length < val.answer_number) {
				arr.push(dataSet[key]);
			}
		}
		arr = me.sortByField(arr, 'job_number');

		var len = arr.length
		for (var i = 0; i < len; i++) {
			if (len == i + 1) { //数组中最后一个
				data = arr[0] || null;
			} else {
				if (Object.keys(arr[i].callers).length > Object.keys(arr[i + 1].callers).length) {
					data = arr[i + 1];
				} else {
					data = arr[i];
				}
				break;
			}
		}
		return data;
	}
};

var kefuHelper = {
	allocation_type: 0, // 0为自动，1为手动
	auto_connect: 1,
	default_message: '',
	group_info: {}, // 手动分配，的分组信息
	init: function () {
		var me = this;
		me.getConfig();
		me.getGroupInfo();
		KeFuModel.closeLink();
	},
	getConfig: function () {
		var me = this;
		// 从本地数据库获取管理员的信息
		KeFuModel.getGlobalConfig(function (result, flag) {
			if (Object.keys(result).length > 0) {
				result.forEach(function (row) {
					if (row && row.config_key && row.config_val) {
						if (me.hasOwnProperty(row.config_key)) {
							me[row.config_key] = row.config_val;
						}
					}
				});
			}
		});
	},
	getGroupInfo: function () {
		var me = this;
		// 从本地数据库获取分组信息
		KeFuModel.getGroup(function (result, flag) {
			if (Object.keys(result).length > 0) {
				result.forEach(function (row) {
					me.group_info[row.group_id] = {
						group_id: row.group_id,
						group_name: row.group_name,
						online_number: 0
					};
				});
			}
		});
	},
	// 根据配置，对访客做出响应
	allocating: function (fn) {
		var me = this;
		if (me.allocation_type == 0) {
			me.autoAllocation(fn);
		} else {
			me.manualAllocation(fn);
		}
	},
	// 自动分配，
	autoAllocation: function (fn) {
		// 抓一个客服，为访客服务
		var user = adminHelper.catchOne(),
			adminJoinId = user && user.join_id ? user.join_id : null;
		if (adminHelper.isJoinId(adminJoinId)) {
			servModule.informAdmin(adminJoinId, jo); // TODO 自动分配功能还没有加进来 error
		}
		else {

		}
	},
	// 手动分配，
	manualAllocation: function (fn) {
		var me = this,
			groupInfo = me.group_info,
			keys = Object.keys(groupInfo);
		if (keys.length > 0) {
			keys.forEach(function (groupId) {
				groupInfo[groupId].online_number = 0;
			});
			var keys = Object.keys(adminList);
			if (keys.length > 0) {
				keys.forEach(function (adminId) {
					var admin = adminList[adminId],
						gid = admin.group_id;
					if (groupInfo.hasOwnProperty(gid)) {
						groupInfo[gid].online_number += 1;
					} else {
						console.log('没有设置分组客服:' + JSON.stringify(admin));
					}
				});
			}
		}
		fn && fn.call(this);
	}
};
kefuHelper.init();

kefu.on('connection', function (socket) {

	// 访客发来的消息
	socket.on('message', function (jsonStr) {
		var jo = JSON.parse(jsonStr);
		if (jo && jo.from && jo.to && jo.message) {
			socket.to(jo.to).emit('message', jsonStr);
		}
	});

	// 访客发来的消息
	socket.on('controller', function (jo) {
		if (jo && jo.action && servModule[jo.action]) {
			servModule[jo.action].call(this, jo);
		}
	});

	// 访客正在输入
	socket.on('inputing', function (jo) {
		if (jo && jo.from && jo.to) {
			socket.to(jo.to).emit('prefetch', jo); //预读取
		}
	});

	// 访客入口，登记来访用户，为来访用户分配客服
	socket.on('register', function (jo) {
		if (jo && jo.join_id) {
			var joinId = jo.join_id;
			userHelper.record(jo);
			socket.joinId = joinId; // TODO Maybe have BUG
			socket.join(joinId);

			kefuHelper.allocating(function () {
				var that = this;
				if (that.allocation_type == 0) { // 自动

				} else { // 手动
					var resp = {};
					resp.allocation_type = that.allocation_type;
					resp.group_info = that.group_info;
					resp.default_message = that.default_message;
					servModule.informUser(joinId, resp); // 通知访客，应答他的客服ID，访客客户端将缓存该客服ID
				}
			});
		}
	});

	// 回复访客，为其服务的客服信息
	socket.on('replyCaller', function (jo) {
		if (jo && jo.joinId && jo.callerJoinId) {
			var callerJoinId = jo.callerJoinId,
				serviceId = jo.joinId,
				callerInfo = userHelper.getUserInfo(callerJoinId);

			// 通知双方建立连接
			var noticeEachother = function (jo, respObj, adminStatus) {
				callerInfo.isReply = 1; // 将访客的应答状态设置为，有人应答
				adminHelper.changeStaus(jo.adminId, adminStatus); // 改变客服状态

				var userInfo = jo.caller;
				userInfo.talkId = respObj.talkId;

				servModule.informServiceToCreateDialog(jo.joinId, userInfo);
				if (jo.allocation_type == 1) {
					servModule.informUser(callerJoinId, respObj, 1);
				} else {
					servModule.informUser(callerJoinId, respObj, 0); // 通知访客，应答他的客服ID，访客客户端将缓存该客服ID
				}
			};

			if (callerInfo.isReply === 0) { // 如果访客的信息还没有被应答
				var adminStatus,
					respObj = {};
				if (jo.status == 1) { // 1 为接受，其它为拒绝
					adminStatus = 2;
					respObj.serviceId = serviceId;
					respObj.sysMessage = '尊敬的访客&nbsp;:&nbsp;您好，欢迎访问KACN客服平台，我们将竭诚为您提供优质、专业的服务！<br/>系统为您安排了"' + jo.csName + '"，祝您购物愉快！'; // 可返回系统预设消息
					respObj.welcome = jo.welcome;
					servModule.createTalk(jo, function (result) {
						var insertId = result.insertId;
						if (insertId > 0) { // 获取到谈话编号成功
							respObj.talkId = insertId;
							noticeEachother(jo, respObj, adminStatus);

							userHelper.setUserAttr(callerJoinId, 'serviceId', serviceId); //设置应答访客的客服ID;
							userHelper.setUserAttr(callerJoinId, 'talkId', insertId); //设置应答访客的客服ID;
							// TODO 还需要在客服里记录一下应答访客的ID
						}
					});
				} else {
					adminStatus = 0;
					respObj.serviceId = 0;
					respObj.sysMessage = '暂无空闲客服，请稍候重试';
					beforeInformUser(jo, respObj, adminStatus);
				}
			}
		}
	});

	// 管理员入口
	socket.on('adminJoinIn', function (jsonStr) {
		var jo = JSON.parse(jsonStr);
		var adminId = jo.user_id,
			token = jo.token,
			whereArr = [adminId];
		// 从本地数据库获取管理员的信息
		KeFuModel.getAdminInfo(whereArr, function (result, flag) {
			if (result && result.user_id > 0) {
				var joinId = 'a' + result.user_id;
				result.join_id = joinId;
				adminHelper.initAdminInfo(result);
				// 返回在线的管理员列表，及用户列表
				var obj = {};
				obj.message = ['与服务器建立连接成功'];
				obj.self = {
					uid: result.user_id,
					join_id: joinId,
					username: result.user_name,
					job_number: result.job_number
				};
				obj.user = userList;
				obj.admin = adminList;
				servModule.welcome(obj);

				socket.joinId = joinId;
				socket.join(joinId);
			}
		});
	});

	// 访客选择了某一分组
	socket.on('connectGroup', function (jo) {
		if (jo) {
			var groupId = jo.group_id;
			var admin = adminHelper.catchOneFromGroup(groupId),
				adminJoinId = admin && admin.join_id ? admin.join_id : null;
			if (adminHelper.isJoinId(adminJoinId)) {
				servModule.informAdmin(adminJoinId, jo);
			}
			else {
				console.log('客服不存在。');
			}
		}
	});

	// 当某个链接断开时，更新相应的列表
	socket.on('disconnect', function () {
		var uid = socket.joinId;
		if (/^u/.test(uid)) {
			var callerJoinId = socket.joinId,
				joinId = userHelper.getUserAttr(callerJoinId, 'serviceId');
			delete userList[callerJoinId];
			servModule.serviceChangeCallerStatus(joinId, callerJoinId, 2);
		} else if (/^a/.test(uid)) {
			delete adminList[socket.joinId];
		}
	});

	socket.on('grade', function (obj) {
		if (obj && obj.talkId) {
			var dataArr = [],
				unlinkTime = parseInt(Date.now() / 1000);
			dataArr.push(obj.score);
			dataArr.push(obj.evaluation);
			dataArr.push(unlinkTime);
			dataArr.push(obj.talkId);
			KeFuModel.updateTalk(dataArr, function (result) {
				if (result && result.affectedRows > 0) {
					socket.emit('gradeResponed', 'gradeSuccess');
				}
			});
		} else {

		}
	});

	/**
	 * 从服务器获取用户列表
	 * flag = 1 为获取在线客服列表
	 */
	socket.on('userList', function (flag) {
		if (flag === 1) {
			socket.emit('userListResponded', adminList);
		}
	});

	/**
	 * 将转接请求发送给需要接入的客服
	 */
	socket.on('passToService', function (obj) {
		if (obj) {
			var joinId = obj.toJoinId;
			obj.userInfo = userHelper.getUserInfo(obj.callerJoinId);
			socket.to(joinId).emit('requestHandover', obj);
		}
	});

	/**
	 * 被转接的客服是否同意接入
	 * 20150717
	 * var obj = { toJoinId: 'a111', msg: 'kkkk', fromUsername: '0130号客服专员', fromJoinId: a30, callerJoinId: 'u_62e3db9039ed50fee61b9500a70ad6fe', callerName: 'u55a36712298f8', isAgree: 1 };
	 */
	socket.on('requestHandoverResp', function (obj) {
		if (obj) {
			if (obj.isAgree == 1) { // 同意
				// 新应答客服(A)同意接收访客后，需要先通知之前的客服(B)，改变B客服用户列表中的用户状态。
				// 同时A客服与访客之前建立通话连接
				servModule.serviceChangeCallerStatus(obj.fromJoinId, obj.callerJoinId, 3);
				// 改变访客当前对话客服的ID

				console.log(obj);
				servModule.changeCallerServiceId(obj.callerJoinId, obj.toJoinId, obj.fromJobNumber);
			} else { // 拒绝
				obj.action = 'rejectHandover';
				socket.to(obj.fromJoinId).emit('controller', obj);
			}
		}
	});

	var servModule = {
		// 客服管理员连接后，返回给管理员在线用户的列表，及管理员列表
		welcome: function (obj) {
			socket.emit('welcome', obj);
		},
		// 通知用户与其对话的管理员信息
		informUser: function (callerJoinId, respObj, flag) {
			//flag=1时，表示访客手动选择分组，否则为自动连接
			if (flag == 1) {
				socket.to(callerJoinId).emit('connectGroupResponded', respObj);
			} else {
				if (callerJoinId == socket.joinId) {
					socket.emit('registerResponded', respObj);
				} else {
					socket.to(callerJoinId).emit('registerResponded', JSON.stringify(respObj));
				}
			}
		},
		// 通知客服，有访客接入
		informAdmin: function (joinId, uo) {
			socket.to(joinId).emit('inform', uo);
		},
		// 通知客服，创建对话窗口
		informServiceToCreateDialog: function (adminJoinId, uo) {
			adminHelper.addCallerToList(adminJoinId, uo);
			uo.action = 'setNewCaller';
			socket.emit('controller', uo);
		},
		createTalk: function (jo, fn) {
			var data = {};
			data.caller_id = jo.uid;
			data.service_id = jo.adminId;
			data.caller_name = jo.caller_name;
			data.ip = jo.ip;
			data.link_time = parseInt(Date.now() / 1000);
			KeFuModel.createTalk(data, function (result) {
				fn && fn.call(null, result);
			});
		},

		serviceChangeCallerStatus: function (joinId, callerJoinId, status) {
			var jo = {};
			jo.action = 'setCallerStatus';
			jo.callerJoinId = callerJoinId;
			jo.flag = status; // 转接

			socket.to(joinId).emit('controller', jo); // 通知提出转接的客服，访客被接手，需要将该客服与访客之间的连接断开，并且设置用户列表的状态
		},

		//改变访客当前对话的访客
		changeCallerServiceId: function (callerJoinId, joinId, fromJobNumber) {
			var jo = {};
			jo.action = 'switchToService';
			jo.joinId = joinId;
			jo.fromJobNumber = fromJobNumber;
			socket.to(callerJoinId).emit('controller', jo);
		},

		// 发送消息的接口
		message: function (jo) {
			if (jo && jo.from && jo.to && jo.message) {
				jo.action = 'getMessage';
				if (jo.message.length > 0 && jo.message.length <= 256) {
					var data = {};
					data.talk_id = jo.talk_id;
					data.join_id = jo.from;
					data.to_join_id = jo.to;
					data.message = jo.message;
					var nowStamp = parseInt(Date.now() / 1000);
					data.send_time = nowStamp;

					KeFuModel.recordChat(data, function (result) {
						socket.to(jo.to).emit('controller', jo);
					});
				}
			}
		},

		// 客服获取最新的聊天记录
		getRecentMessage: function (jo) {
			if (jo) {
				var talkId = jo.talkId;
				var whereArr = [talkId];
				KeFuModel.getChatList(whereArr, function (result) {
					var dao = {};
					dao.action = 'pullRecentMessageResp';
					dao.callerJoinId = jo.callerJoinId;
					dao.result = result;
					socket.emit('controller', dao);
				});
			}
		},

		/**
		 * 客服获取访客状态
		 * @param jo
		 */
		getCallerStatus: function (jo) {
			if (jo && jo.callerJoinId) {
				jo.action = 'getCallerStatusResponded';
				var toJoinId = jo.callerJoinId;
				socket.to(toJoinId).emit('controller', jo);
			}
		},

		/**
		 * 访客响应客服
		 * @param jo
		 */
		getCallerStatusResponded: function (jo) {
			if (jo && jo.joinId) {
				var toJoinId = jo.joinId;
				socket.to(toJoinId).emit('controller', jo);
			}
		},
		/**
		 * 客服断开与访客的连接
		 */
		offlineCaller: function (jo) {
			if (jo && jo.callerJoinId) {
				var obj = {action: 'offlineByService'};
				socket.to(jo.callerJoinId).emit('controller', obj);
			}
		}
	};
});
console.log('kefu server is ready!');